﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WorkStation.Frameworks.Core.Extensions;
using WorkStation.Frameworks.EasyBus.Pipeline.Modules;

namespace WorkStation.Frameworks.EasyBus.Pipeline
{
    /// <summary>
    /// 对象管道
    /// </summary>
    public class ObjectPipeline : IPipeline
    {
        public event Action<ActionContext, SuccessHandleResult> OnSuccess;
        public event Action<ActionContext, FailHandleResult> OnFail;
        public event Action<ActionContext> OnPublishBefore;
        public event Action<ActionContext, IEnumerable<HandleResult>> OnPublishAfter;

        public Dictionary<string, IModule> Modules { get; set; }

        public ObjectPipeline()
        {
            this.Modules = new Dictionary<string, IModule>();
        }

        /// <summary>
        /// 发布
        /// </summary>
        /// <param name="context">执行上下文</param>
        /// <returns></returns>
        public IEnumerable<HandleResult> Publish(ActionContext context)
        {
            if (this.OnPublishBefore != null) 
            {
                this.OnPublishBefore(context);
            }

            List<HandleResult> results = Modules.Select(v => v.Value).OrderBy(v => v.Order).SelectMany(v => v.Process(context)).ToList();

            // 错误结果在发布到管道中
            results.Where(v => v is FailHandleResult).ForEach(v =>
            {
                if (this.OnFail != null) { this.OnFail(context, v as FailHandleResult); }
            });

            // 成功结果在发布到管道中
            results.Where(v => v is SuccessHandleResult).ForEach(v =>
            {
                if (this.OnSuccess != null) { this.OnSuccess(context, v as SuccessHandleResult); }
            });

            if (this.OnPublishAfter != null) 
            {
                this.OnPublishAfter(context, results);
            }

            return results;
        }

        /// <summary>
        /// 发布
        /// </summary>
        /// <param name="input">对象</param>
        /// <returns></returns>
        public IEnumerable<HandleResult> Publish(object input)
        {
            if (input is ActionContext) 
            {
                return this.Publish(input as ActionContext);
            }

            ActionContext context = new ActionContext() { Input = input };

            return this.Publish(context);
        }
    }
}
